#include "pthread.h"
#include <vector>
#include <queue>
#include <string>
#include <functional>

struct thread_info
{
    pthread_t _tid;
    std::string _name;
};

template <typename T>
class thread_pool
{
    static const int default_num = 5;
private:
    void lock() { pthread_mutex_lock(&_mutex); }
    void unlock() { pthread_mutex_unlock(&_mutex); }
    void thread_sleep() { pthread_cond_wait(&_cond, &_mutex); }
    void thread_wakeup() { pthread_cond_signal(&_cond); }

    std::string get_thread_name(pthread_t tid)
    {
        for (const auto &e : _threads)
            if (e._tid == tid)
                return e._name;
        return "none";
    }
    //  对于类内函数，存在一个隐含的实参(this指针，为了解决这一个问题，需要使用static成员函数作为线程的函数)
    //  可是static无法使用类内成员，所以可以降this指针作为实参传递给routine函数
    void thread_routine()
    {
        // 1. 获取数据
            lock();
            while (_tasks.empty())
                thread_sleep();
            T t = pop();
            unlock();
            // 2. 处理数据
            t.run();
            printf("%s 处理了一个任务%s\n", get_thread_name(pthread_self()).c_str(), t.get_result().c_str());
    }

    static void *thread_task(void *args)
    {
        thread_pool<T> *ptp = static_cast<thread_pool<T> *>(args);
        auto routine = std::bind(&thread_pool::thread_routine, ptp);
        while(true)
            routine();
        return nullptr;
    }

public:
    bool is_empty() { return _tasks.empty(); }

    thread_pool(int num = default_num)
        : _threads(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~thread_pool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void start()
    {
        int i = 1;
        for (auto &e : _threads)
        {

            e._name = "thread " + std::to_string(i++);
            pthread_create(&(e._tid), nullptr, thread_task, this);
        }
    }

    void push(const T &t)
    {
        lock();
        _tasks.push(t);
        unlock();
        thread_wakeup();
    }

    T pop()
    {
        T t = _tasks.front();
        _tasks.pop();
        unlock();
        return t;
    }

private:
    std::vector<thread_info> _threads;
    // 线程之间需要有同步关系, 用条件变量实现
    pthread_cond_t _cond;
    // 任务队列
    std::queue<T> _tasks;
    // 在操作任务队列时需要加锁
    pthread_mutex_t _mutex;
};